package com.sz.app.oss.api.dashboard;

import com.sz.app.oss.api.dashboard.dto.StatisticsDto;
import com.sz.app.oss.api.dashboard.dto.SummaryDto;
import com.sz.app.oss.api.dashboard.dto.WeeklyStaticsDto;
import com.sz.biz.app.web.BaseController;
import com.sz.biz.common.base.dto.AreaDto;
import com.sz.biz.common.base.entity.Country;
import com.sz.biz.common.base.service.AreaManager;
import com.sz.biz.logistics.constants.ErrorCodes;
import com.sz.biz.rpt.entity.*;
import com.sz.biz.rpt.service.*;
import com.sz.common.base.dto.ResultDto;
import com.sz.common.base.exception.Exceptions;
import com.sz.common.base.utils.DateUtils;
import com.sz.common.base.utils.StringUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Function: 驾驶舱统计controller <br>
 *
 * @author fengwj <br>
 *         Date: 2017-12-04 17:01:00
 */
@RestController
@RequestMapping("/api/v1/dashboard")
@Api(description = " ", tags = "060、驾驶舱统计")
public class DashboardController extends BaseController {

    @Autowired
    private RptSaleSummaryService rptSaleSummaryService;

    @Autowired
    private RptSaleProductService rptSaleProductService;

    @Autowired
    private RptSaleSupplierService rptSaleSupplierService;

    @Autowired
    private RptSaleCustomerService rptSaleCustomerService;

    @Autowired
    private RptSaleAreaService rptSaleAreaService;

    @Autowired
    private AreaManager areaManager;

    /**
     * 物流
     */
    private final static String LOGISTICS = "logistics";
    /**
     * 产品
     */
    private final static String PRODUCT = "product";

    /**
     * 供应商
     */
    private final static String SUPPLIER = "supplier";
    /**
     * 客户
     */
    private final static String CUSTOMER = "customer";
    /**
     * 年
     */
    private final static String YEAR = "year";
    /**
     * 季度
     */
    private final static String QUARTER = "quarter";
    /**
     * 月
     */
    private final static String MONTH = "month";
    /**
     * 周
     */
    private final static String WEEK = "week";
    /**
     * 交易额
     */
    private final static String AMOUNT = "amount";
    /**
     * 订单数量
     */
    private final static String ORDER = "order";
    /**
     * 货量
     */
    private final static String VOLUME = "volume";
    /**
     * 数据单位：千克
     */
    private final static String TON = "吨";
    /**
     * 地区或城市
     */
    private final static String REGION = "region";

    private final static String BILL = "单";

    private final static String ONE_CNY = "CNY";
    private final static String CN = "cn";


    @ApiOperation(value = "按时间范围统计", notes = "按时间统计业务类型、交易额、订单量、货量、供应商数量、客户数量等")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "startDate", value = "查询条件开始时间(yyyy-MM-dd)", dataType = "string", paramType = "query"),
            @ApiImplicitParam(name = "endDate", value = "查询条件结束时间(yyyy-MM-dd)", dataType = "string", paramType = "query")
    })
    @RequestMapping(value = "/summary", method = {RequestMethod.GET})
    public ResultDto countByDate(@RequestParam(required = false, defaultValue = "") String startDate,
                                 @RequestParam(required = false, defaultValue = "") String endDate) {

        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        List<StatisticsDto> statisticsDtoList = new ArrayList<>();

        //检查参数
        Map<String, Object> params = new HashMap<>(16);
        try {
            params.put("startDate", StringUtils.isEmpty(startDate) ? null : format.parse(startDate));
        } catch (ParseException e) {
            throw Exceptions.bizException(ErrorCodes.ERROR_ARGUMENT_ILLEGAL, "startDate");
        }
        try {
            params.put("endDate", StringUtils.isEmpty(endDate) ? null : format.parse(endDate));
        } catch (ParseException e) {
            throw Exceptions.bizException(ErrorCodes.ERROR_ARGUMENT_ILLEGAL, "endDate");
        }

        //汇总
        RptSaleSummary summary = rptSaleSummaryService.findByParam(params);

        if (summary == null) {
            summary = new RptSaleSummary();
            summary.setLogisticsAmount(BigDecimal.ZERO);
            summary.setLogisticsVolume(BigDecimal.ZERO);
            summary.setLogisticsBillCount(0);
            summary.setLogisticsNewCustCount(0);
            summary.setLogisticsNewSupCount(0);
            summary.setTradeAmount(BigDecimal.ZERO);
            summary.setTradeVolume(BigDecimal.ZERO);
            summary.setTradeBillCount(0);
            summary.setTradeNewCustCount(0);
            summary.setTradeNewSupCount(0);
        }
        BigDecimal logisticsAmount = summary.getLogisticsAmount();
        BigDecimal tradeAmount = summary.getTradeAmount();


        summary.setLogisticsVolume(summary.getLogisticsVolume().setScale(2, BigDecimal.ROUND_HALF_UP));
        summary.setTradeVolume(summary.getTradeVolume().setScale(2, BigDecimal.ROUND_HALF_UP));

        statisticsDtoList.add(new StatisticsDto(
                AMOUNT,
                "交易额",
                logisticsAmount.add(tradeAmount),
                logisticsAmount,
                tradeAmount,
                ONE_CNY));

        statisticsDtoList.add(new StatisticsDto(
                ORDER,
                "订单数量",
                new BigDecimal(summary.getLogisticsBillCount() + summary.getTradeBillCount()),
                new BigDecimal(summary.getLogisticsBillCount()),
                new BigDecimal(summary.getTradeBillCount()),
                BILL));

        statisticsDtoList.add(new StatisticsDto(
                VOLUME,
                "货量",
                summary.getLogisticsVolume().add(summary.getTradeVolume()),
                summary.getLogisticsVolume(),
                summary.getTradeVolume(),
                TON));

        statisticsDtoList.add(new StatisticsDto(
                SUPPLIER,
                "供应商",
                new BigDecimal(summary.getLogisticsNewSupCount() + summary.getTradeNewSupCount()),
                new BigDecimal(summary.getLogisticsNewSupCount()),
                new BigDecimal(summary.getTradeNewSupCount()), ""));

        statisticsDtoList.add(new StatisticsDto(
                CUSTOMER,
                "客户",
                new BigDecimal(summary.getLogisticsNewCustCount() + summary.getTradeNewCustCount()),
                new BigDecimal(summary.getLogisticsNewCustCount()),
                new BigDecimal(summary.getTradeNewCustCount()), ""));

        ResultDto result = new ResultDto();
        result.setData(statisticsDtoList);
        return result;
    }


    @ApiOperation(value = "按业务类型统计上个月周期数据，分为交易额，订单数，货量", notes = "按业务类型统计上个月周期数据，分为交易额，订单数，货量")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "biz", value = "物流logistics、贸易trade", required = true, dataType = "string", paramType = "path"),
            @ApiImplicitParam(name = "biztype", value = "数据类型：amount(交易额)，order(订单数)，volume(货量)", required = true, dataType = "string", paramType = "path")
    })
    @RequestMapping(value = "/summary/first/{biz}/{biztype}", method = {RequestMethod.GET})
    public ResultDto countLastPeriod(@PathVariable String biz, @PathVariable String biztype) throws ParseException {

        Map<String, List<SummaryDto>> resultMap = new HashMap<>(4);
        //输入参数验证
        if (StringUtils.isEmpty(biztype)) {
            throw (Exceptions.bizException(ErrorCodes.ERROR_ARGUMENT_ILLEGAL, "biztype"));
        }

        Map<String, Object> param = new HashMap<>(16);
        param.put("startDate", DateUtils.getLastMonthFirstDay());
        param.put("endDate", DateUtils.getLastMonthLastDay());
        param.put("biz", LOGISTICS.equals(biz) ? 1 : 2);
        param.put("sort", biztype);
        //产品
        List<RptSaleProduct> rsps = rptSaleProductService.findByParam(param);
        List<SummaryDto> productList = rsps.stream().map(item -> handlerRptItem(biztype, item.getProductName(),
                item.getAmount(), item.getBillCount(), item.getVolume())).collect(Collectors.toList());
        resultMap.put(PRODUCT, productList);
        //供应商
        List<RptSaleSupplier> rsss = rptSaleSupplierService.findByParam(param);
        List<SummaryDto> supplierList = rsss.stream().map(item -> handlerRptItem(biztype, item.getSupplierName(),
                item.getAmount(), item.getBillCount(), item.getVolume())).collect(Collectors.toList());
        resultMap.put(SUPPLIER, supplierList);
        //客户
        List<RptSaleCustomer> rscs = rptSaleCustomerService.findByParam(param);
        List<SummaryDto> customerList = new ArrayList<>();
        rscs.forEach(item -> customerList.add(handlerRptItem(biztype, item.getCustomerName(),
                item.getAmount(), item.getBillCount(), item.getVolume())));
        resultMap.put(CUSTOMER, customerList);

        //国内地区
        param.put("region", "cn");
        List<RptSaleArea> rsas = rptSaleAreaService.findByParam(param);
        List<SummaryDto> areaList = new ArrayList<>();
        rsas.forEach(item -> {
                    //areaM  获取经纬度
                    List<AreaDto> areas = areaManager.findByAreaId(item.getCountryId(), item.getCityId());
                    SummaryDto dto = handlerRptItem(biztype, item.getCityName(),
                            item.getAmount(), item.getBillCount(), item.getVolume());
                    if (!CollectionUtils.isEmpty(areas)) {
                        AreaDto area = areas.get(0);
                        dto.setLongitude(area.getLng() == null ? 0 : area.getLng().floatValue());
                        dto.setLatitude(area.getLat() == null ? 0 : area.getLat().floatValue());
                    } else {
                        dto.setLongitude(0);
                        dto.setLatitude(0);
                    }
                    areaList.add(dto);
                }
        );
        resultMap.put(REGION, areaList);


        ResultDto result = new ResultDto();
        result.setData(resultMap);
        return result;
    }


    @ApiOperation(value = "按条件查询某一类业务排序数据", notes = "按条件查询某一类业务排序数据")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "biz", value = "物流logistics、贸易trade", required = true, dataType = "string", paramType = "path"),
            @ApiImplicitParam(name = "biztype", value = "数据类型：amount(交易额)，order(订单数)，volume(货量)", required = true, dataType = "string", paramType = "path"),
            @ApiImplicitParam(name = "scope", value = "数据类型：product(产品)，supplier(供应商)，customer(客户)，region(地区或城市)", required = true, dataType = "string", paramType = "query"),
            @ApiImplicitParam(name = "period", value = "统计周期：year(年)，quarter(季度)，month(月)，week(周)", required = true, dataType = "string", paramType = "query"),
            @ApiImplicitParam(name = "regiontype", value = "地图区域：country（全部国家）,cn（中国）", required = true, dataType = "string", paramType = "query")
    })
    @RequestMapping(value = "/summary/{biz}/{biztype}", method = {RequestMethod.GET})
    public ResultDto countLastAreas(@PathVariable String biz, @PathVariable String biztype,
                                    @RequestParam String scope,
                                    @RequestParam String period, @RequestParam String regiontype) throws ParseException {
        ResultDto result = new ResultDto();
        Map<String, List<SummaryDto>> resultMap = new HashMap<>(16);
        //输入参数验证
        if (StringUtils.isEmpty(biztype)) {
            throw (Exceptions.bizException(ErrorCodes.ERROR_ARGUMENT_ILLEGAL, "biztype"));
        }
        if (StringUtils.isEmpty(scope)) {
            throw (Exceptions.bizException(ErrorCodes.ERROR_ARGUMENT_ILLEGAL, "scope"));
        }
        if (StringUtils.isEmpty(period)) {
            throw (Exceptions.bizException(ErrorCodes.ERROR_ARGUMENT_ILLEGAL, "period"));
        }

        Date startDate;
        Date endDate;
        switch (period) {
            case YEAR:
                startDate = DateUtils.getLastYearFirstDay();
                endDate = DateUtils.getLastYearLastDay();
                break;
            case QUARTER:
                startDate = DateUtils.getFirstDayOfLastQuarter();
                endDate = DateUtils.getLastDayOfLastQuarter();
                break;
            case MONTH:
                startDate = DateUtils.getLastMonthFirstDay();
                endDate = DateUtils.getLastMonthLastDay();
                break;
            case WEEK:
                startDate = DateUtils.getLastWeekFirstDay();
                endDate = DateUtils.getLastWeekLastDay();
                break;
            default:
                throw (Exceptions.bizException(ErrorCodes.ERROR_ARGUMENT_ILLEGAL, "period"));
        }

        Map<String, Object> param = new HashMap<>(16);
        param.put("startDate", startDate);
        param.put("endDate", endDate);
        param.put("biz", LOGISTICS.equals(biz) ? 1 : 2);
        param.put("sort", biztype);
        //product(产品)，supplier(供应商)，customer(客户)，region(地区或城市)
        switch (scope) {
            case PRODUCT:
                List<RptSaleProduct> rsps = rptSaleProductService.findByParam(param);
                List<SummaryDto> productList = new ArrayList<>();
                rsps.forEach(item -> productList.add(handlerRptItem(biztype, item.getProductName(),
                        item.getAmount(), item.getBillCount(), item.getVolume())));
                resultMap.put(PRODUCT, productList);
                break;
            case CUSTOMER:
                List<RptSaleCustomer> rscs = rptSaleCustomerService.findByParam(param);
                List<SummaryDto> customerList = new ArrayList<>();
                rscs.forEach(item -> customerList.add(handlerRptItem(biztype, item.getCustomerName(),
                        item.getAmount(), item.getBillCount(), item.getVolume())));
                resultMap.put(CUSTOMER, customerList);
                break;
            case SUPPLIER:
                List<RptSaleSupplier> rsss = rptSaleSupplierService.findByParam(param);
                List<SummaryDto> supplierList = new ArrayList<>();
                rsss.forEach(item -> supplierList.add(handlerRptItem(biztype, item.getSupplierName(),
                        item.getAmount(), item.getBillCount(), item.getVolume())));
                resultMap.put(SUPPLIER, supplierList);
                break;
            case REGION:
                param.put("region", regiontype);
                List<RptSaleArea> rsas = rptSaleAreaService.findByParam(param);
                List<SummaryDto> areaList = new ArrayList<>();
                rsas.forEach(item -> {
                            //areaM  获取经纬度
                            String areaName;

                            float lng = 0;
                            float lat = 0;
                            if (CN.equals(regiontype)) {
                                List<AreaDto> areas = areaManager.findByAreaId(item.getCountryId(), item.getCityId());
                                if (!CollectionUtils.isEmpty(areas)) {
                                    AreaDto area = areas.get(0);
                                    lng = area.getLng() == null ? 0 : area.getLng().floatValue();
                                    lat = area.getLat() == null ? 0 : area.getLat().floatValue();
                                }
                                areaName = item.getCityName();
                            } else {
                                Country country = areaManager.findByCountryCode(item.getCountryId());
                                if (country != null) {
                                    lng = country.getLng() == null ? 0 : country.getLng().floatValue();
                                    lat = country.getLat() == null ? 0 : country.getLat().floatValue();
                                }
                                areaName = item.getCountryName();
                            }

                            SummaryDto dto = handlerRptItem(biztype, areaName,
                                    item.getAmount(), item.getBillCount(), item.getVolume());


                            dto.setLongitude(lng);
                            dto.setLatitude(lat);

                            areaList.add(dto);
                        }
                );
                resultMap.put(REGION, areaList);
                break;
            default:
                //do nothing
        }

        result.setData(resultMap);
        return result;
    }

    @ApiOperation(value = "查询驾驶舱的每周统计", notes = "查询驾驶舱的每周统计")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "type", value = "类型：logistics(物流)，trade(贸易)", required = true, dataType = "string", paramType = "path"),
            @ApiImplicitParam(name = "startDate", value = "开始时间", dataType = "string", paramType = "query"),
            @ApiImplicitParam(name = "endDate", value = "结束时间", dataType = "string", paramType = "query")
    })
    @RequestMapping(value = "/week/{type}", method = {RequestMethod.GET})
    public ResultDto countWeekly(@PathVariable String type,
                                 @RequestParam(required = false, defaultValue = "") String startDate,
                                 @RequestParam(required = false, defaultValue = "") String endDate) throws ParseException {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");

        //检查参数
        Map<String, Object> params = new HashMap<>(16);
        try {
            params.put("startDate", StringUtils.isEmpty(startDate) ? null : format.parse(startDate));
        } catch (ParseException e) {
            throw Exceptions.bizException(ErrorCodes.ERROR_ARGUMENT_ILLEGAL, "startDate");
        }
        try {
            params.put("endDate", StringUtils.isEmpty(endDate) ? null : format.parse(endDate));
        } catch (ParseException e) {
            throw Exceptions.bizException(ErrorCodes.ERROR_ARGUMENT_ILLEGAL, "endDate");
        }

        //汇总
        List<RptSaleSummary> summarys = rptSaleSummaryService.findWeekByParam(params);

        ResultDto result = new ResultDto();
        Map<String, Object> map = new HashMap<>(16);
        map.put("amountUnit", ONE_CNY);
        map.put("volumeUnit", TON);

        List<WeeklyStaticsDto> statisticsList = new ArrayList<>();
        summarys.forEach(item -> {
            WeeklyStaticsDto dto = new WeeklyStaticsDto();
            dto.setYear(item.getYear());
            dto.setWeek(item.getWeek());
            BigDecimal amount = BigDecimal.ZERO;
            Integer billCount = Integer.parseInt("0");
            if (LOGISTICS.equals(type)) {
                amount = item.getLogisticsAmount();
                billCount = item.getLogisticsBillCount();
            } else {
                amount = item.getTradeAmount();
                billCount = item.getTradeBillCount();
            }

            dto.setAmount(amount);
            dto.setBillCount(billCount);


            statisticsList.add(dto);
        });
        map.put("statisticsList", statisticsList);
        result.setData(map);
        return result;
    }


    private SummaryDto handlerRptItem(String biztype, String name,
                                      BigDecimal amount, Integer billCount, BigDecimal volume) {
        SummaryDto dto = null;
        switch (biztype) {
            case AMOUNT:
                dto = new SummaryDto(name, amount, ONE_CNY);
                break;
            case ORDER:
                dto = new SummaryDto(name, new BigDecimal(billCount), BILL);
                break;
            case VOLUME:
                dto = new SummaryDto(name, volume, TON);
                break;
            default:
                //do nothing
        }

        return dto;
    }
}
